package sophie.map;

import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class ListMap<K, V> extends AbstractMap<K, V> implements Map<K, V> {

	private List<Node<K, V>> table;
	
	public ListMap() {
		this.table = new ArrayList<Node<K,V>>();
	}
	
	
	@Override
	public V put(K key, V value) {
		Node<K, V> node = node(key);
		if (node == null) {
			table.add(new Node<>(key.hashCode(), key, value, null));
		} else {
			V oldValue = node.getValue();
			node.setValue(value);
			return oldValue;
		}
		return value;
	}


	private Node<K, V> node(K key) {
		Node<K, V> node = null;
		Iterator<Node<K, V>> it = table.iterator();
		while(true) {
			if (! it.hasNext()) {
				break;
			}
			node = it.next();
			if (node.getKey().equals(key)) {
				return node;
			}
		}
		return null;
	}


	@Override
	public Set<Map.Entry<K, V>> entrySet() {
		return new EntrySet();
	}

	private class EntrySet extends AbstractSet<Entry<K, V>> {

		@Override
		public Iterator<Entry<K, V>> iterator() {
			return new Itr();
		}

		@Override
		public int size() {
			return table.size();
		}
		
	}
	
	private class Itr implements Iterator<Entry<K, V>> {

		private int index;
		private Entry<K, V> prev;
		
		@Override
		public boolean hasNext() {
			return index < table.size();
		}

		@Override
		public Entry<K, V> next() {
			prev = table.get(index++);
			return prev;
		}
		
		@Override
		public void remove() {
			table.remove(prev);
		}
		
	}
	
	
	private static class Node<K, V> implements Map.Entry<K, V> {

		int hash;
		K k;
		V v;
		Entry<K, V> next;
		
		public Node(int hash, K k, V v, java.util.Map.Entry<K, V> next) {
			super();
			this.hash = hash;
			this.k = k;
			this.v = v;
			this.next = next;
		}

		@Override
		public K getKey() {
			return k;
		}

		@Override
		public V getValue() {
			return v;
		}

		@Override
		public V setValue(V value) {
			V oldValue = value;
			v = value;
			return oldValue;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + hash;
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Node other = (Node) obj;
			if (hash != other.hash)
				return false;
			return true;
		}
	}
}
